package top.hcode.hoj.service.admin;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.nutz.filepool.FilePool;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.sagacity.sqltoy.model.MapKit;
import org.sagacity.sqltoy.model.Page;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import top.hcode.hoj.common.LazyDao;
import top.hcode.hoj.dao.CollQuestionDao;
import top.hcode.hoj.dao.CollQuestionOptionDao;
import top.hcode.hoj.dao.collect.ItechCollDao;
import top.hcode.hoj.dao.org.OrgDao;
import top.hcode.hoj.dao.org.OrgUserDao;
import top.hcode.hoj.pojo.dto.OptionDTO;
import top.hcode.hoj.pojo.dto.QuerySampleDTO;
import top.hcode.hoj.pojo.dto.coll.ItechCollCopyDTO;
import top.hcode.hoj.pojo.dto.coll.QueryCollStudentScoreDTO;
import top.hcode.hoj.pojo.dto.coll.QueryItechCollectionStatDTO;
import top.hcode.hoj.pojo.entity.coll.CollQuestion;
import top.hcode.hoj.pojo.entity.coll.CollQuestionOption;
import top.hcode.hoj.pojo.entity.coll.ItechCollection;
import top.hcode.hoj.pojo.vo.coll.CollStudentScoreExportVO;
import top.hcode.hoj.pojo.vo.coll.ItechCollStudentScoreDetailVO;
import top.hcode.hoj.pojo.vo.coll.ItechCollectionStatVO;
import top.hcode.hoj.utils.AliyunOSSUtils;
import top.hcode.hoj.utils.Constants;
import top.hcode.hoj.utils.PageUtil;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author orangej
 * @since 2025-01-21
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class AdminItechCollectionService {
    private final ItechCollDao collDao;
    private final AdminCollUserAnswerService userAnswerService;
    private final OrgDao orgDao;
    private final OrgUserDao orgUserDao;
    private final LazyDao queryDao;
    private final CollQuestionDao questionDao;
    private final CollQuestionOptionDao questionOptionDao;

    private final FilePool filePool;

    public IPage<ItechCollection> getItechCollectionList(QuerySampleDTO form) {
        IPage<ItechCollection> pager = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
                form.getCurrentPage(), form.getLimit());

        QueryWrapper<ItechCollection> query = new QueryWrapper<>();
        if (Strings.isNotBlank(form.getKeyword())) {
            query.like("title", form.getKeyword());
        }
        query.orderByDesc("gmt_create");

        collDao.page(pager, query);
        return pager;
    }

    public ItechCollectionStatVO getItechCollectionStat(QueryItechCollectionStatDTO form, List<String> schoolIdList) {
        Map<String, Object> params = MapKit.startOf("campusId", form.getSchoolId())
                .of("gradeId", form.getGradeId())
                .of("classId", form.getClassId())
                .endOf("schoolIdList", schoolIdList);

        List<String> classIdList = queryDao.queryString("queryClassId", params);
        params.put("classIdList", classIdList);
        params.put("collId", form.getCollId());

        // 统计信息
        ItechCollectionStatVO result = queryDao.selectOne(ItechCollectionStatVO.class, "statCollUserStat", params);

        // 主观题待评分数量
        List<NutMap> judgeStateNumList = userAnswerService.querySubjectiveQuestionJudgeCount(form.getCollId(),
                classIdList);
        if (Lang.isNotEmpty(judgeStateNumList)) {
            int count = judgeStateNumList.stream()
                    .filter(it -> it.getInt("judgeState") == 0)
                    .mapToInt(it -> it.getInt("num"))
                    .findFirst().orElse(0);
            result.setSubjectiveToJudgeCount(count);
        }

        return result;
    }

    public ItechCollection getItechCollection(Long id) {
        return collDao.getById(id);
    }

    public ItechCollection saveItechCollection(ItechCollection itechCollection) {
        collDao.saveOrUpdate(itechCollection);
        return itechCollection;
    }

    public void deleteItechCollection(Long id) {
        collDao.removeById(id);
    }

    /**
     * 查询学生成绩列表 ItechCollStudentScoreDetailVO
     */
    public IPage<ItechCollStudentScoreDetailVO> queryItechCollStudentScoreList(QueryCollStudentScoreDTO form,
                                                                               List<String> schoolIdList) {
        List<String> classIdList = orgDao.queryClassIdOf(form.getClassId(), form.getGradeId(),
                form.getSchoolId(), schoolIdList);
        if (Lang.isEmpty(classIdList)) {
            return PageUtil.toMybatis(new Page<>());
        }

        // 构建查询条件
        Map<String, Object> params = Lang.obj2map(form);
        params.put("classIdList", classIdList);
        params.put("sort", parseSortField(form.getSort()));
        Page<Object> page = new Page<>(form.getLimit(), form.getCurrentPage());
        Page<ItechCollStudentScoreDetailVO> pager = queryDao.findPageBySql(
                page, "queryItechCollStudentScoreVO", params, ItechCollStudentScoreDetailVO.class);

        return PageUtil.toMybatis(pager);
    }

    private String parseSortField(String sort) {
        if (Strings.isBlank(sort)) {
            return null;
        }

        switch (sort) {
            case "objectiveScore":
                return "objective_score";
            case "subjectiveScore":
                return "subjective_score";
            case "totalScore":
                return "total_score";
            default:
                return null;
        }
    }

    @SneakyThrows
    public String exportItechCollStudentScoreList(QueryCollStudentScoreDTO form, List<String> schoolIdList) {
        // 查询活动
        ItechCollection coll = collDao.getById(form.getCollId());
        if (coll == null) {
            throw new IllegalArgumentException("未知的活动 : " + form.getCollId());
        }

        // 查询数据
        IPage<ItechCollStudentScoreDetailVO> pager = queryItechCollStudentScoreList(form, schoolIdList);
        List<ItechCollStudentScoreDetailVO> records = pager.getRecords();

        // 创建Excel文件
        File file = filePool.createFile(".xlsx");

        // 准备导出数据
        List<CollStudentScoreExportVO> exportData = records.stream()
                .map(record -> {
                    CollStudentScoreExportVO score = new CollStudentScoreExportVO();
                    score.setSchoolName(record.getSchoolName());
                    score.setClassName(record.getClassName());
                    score.setUserName(record.getUserName());
                    score.setAccount(record.getAccount());
                    score.setObjectiveScore(record.getObjectiveScore());
                    score.setSubjectiveScore(record.getSubjectiveScore());
                    score.setTotalScore(record.getTotalScore());
                    score.setUsedMinutes(record.getUsedMinutes());
                    return score;
                })
                .collect(Collectors.toList());

        // 写入Excel
        EasyExcel.write(file, CollStudentScoreExportVO.class)
                .sheet("学生成绩")
                .doWrite(exportData);

        return AliyunOSSUtils.uploadFile(new FileInputStream(file), "tmp/" + IdWorker.getIdStr() + ".xlsx");
    }

    public ItechCollStudentScoreDetailVO getItechCollStudentScoreDetail(String userId) {
        Map<String, Object> params = MapKit.startOf("userId", userId).endOf("collId", Constants.DEFAULT_COLL_ID);
        return queryDao.selectOne(ItechCollStudentScoreDetailVO.class, "queryItechCollStudentScoreVO", params);
    }

    // 查询当前用户有效活动
    public List<ItechCollection> queryValidItechCollectionList(String userId) {
        String schoolId = orgUserDao.getStudentSchoolId(userId);
        Integer grade = orgUserDao.getStudentGrade(userId);
        if (Strings.isBlank(schoolId) || grade == null) {
            return new ArrayList<>();
        }

        return collDao.queryListBySchoolAndGrade(schoolId, grade);
    }

    @Cached(cacheType = CacheType.BOTH)
    public List<OptionDTO> getOptions(List<String> schoolIdList) {
        if (Lang.isEmpty(schoolIdList)) {
            return new ArrayList<>();
        }

        LambdaQueryChainWrapper<ItechCollection> query = collDao.lambdaQuery();
        return query.and(q -> {
                    for (String id : schoolIdList) {
                        query.like(ItechCollection::getSchoolList, id)
                                .or();
                    }
                })
                .orderByDesc(ItechCollection::getGmtCreate).list()
                .stream().map(it -> new OptionDTO(it.getCollTitle(), it.getId()))
                .collect(Collectors.toList());
    }

    /**
     * 查询教师可见的活动，只返回已启用的活动
     * @param schoolIdList 学校id列表
     * @return 活动列表
     */
    public List<ItechCollection> queryBySchools(List<String> schoolIdList) {
        if (Lang.isEmpty(schoolIdList)) {
            return new ArrayList<>();
        }

        LambdaQueryChainWrapper<ItechCollection> query = collDao.lambdaQuery();
        return query.and(q -> {
            for (String id : schoolIdList) {
                q.like(ItechCollection::getSchoolList, id)
                        .or();
            }
        })
        .list();
    }

    /**
     * 复制调研活动
     *
     * @param dto 复制参数
     */
    @Transactional
    public void copyItechCollection(ItechCollCopyDTO dto) {
        ItechCollection originalColl = collDao.getById(dto.getCollId());
        if (originalColl == null) {
            throw new IllegalArgumentException("未知的活动 : " + dto.getCollId());
        }

        // 1. 复制 ItechCollection
        ItechCollection newColl = new ItechCollection();
        BeanUtil.copyProperties(originalColl, newColl);
        newColl.setId(null); // MyBatis-Plus 会自动生成新的ID
        newColl.setCollTitle(dto.getName());
        newColl.setGmtCreate(new Date());
        newColl.setGmtModified(new Date());

        collDao.save(newColl); // 保存新的 Collection 以获取 ID

        String newCollId = newColl.getId();
        if (Strings.isBlank(newCollId)) {
            log.error("复制活动失败，新的活动ID为空，原始活动ID: {}", dto.getCollId());
            throw new RuntimeException("复制活动失败，无法获取新的活动ID");
        }

        // 2. 复制 CollQuestion
        List<CollQuestion> originalQuestions = questionDao.lambdaQuery()
                .eq(CollQuestion::getCollId, originalColl.getId())
                .list();
        if (Lang.isEmpty(originalQuestions)) {
            return;
        }

        List<CollQuestion> newQuestions = new ArrayList<>();
        List<CollQuestionOption> allNewOptions = new ArrayList<>();

        for (CollQuestion originalQuestion : originalQuestions) {
            CollQuestion newQuestion = new CollQuestion();
            BeanUtil.copyProperties(originalQuestion, newQuestion);

            newQuestion.setId(null); // MP自动生成
            newQuestion.setCollId(newCollId);
            newQuestion.setGmtCreate(new Date());
            newQuestion.setGmtModified(new Date());
            newQuestions.add(newQuestion);
        }
        questionDao.saveBatch(newQuestions); // 先批量保存所有新题目，以确保它们都有ID

        // 现在 newQuestions 中的每个 question 都有了数据库生成的ID
        // 接下来，为每个新题目复制选项
        for (int i = 0; i < originalQuestions.size(); i++) {
            CollQuestion originalQuestion = originalQuestions.get(i);
            CollQuestion newQuestion = newQuestions.get(i); // 获取对应的新保存的题目

            if (Strings.isBlank(newQuestion.getId())) {
                log.warn("复制题目选项跳过，因为新题目ID为空，原始题目ID: {}", originalQuestion.getId());
                continue;
            }

            List<CollQuestionOption> originalOptions = questionOptionDao.lambdaQuery()
                    .eq(CollQuestionOption::getQuestionId, originalQuestion.getId())
                    .list();

            if (Lang.isNotEmpty(originalOptions)) {
                List<CollQuestionOption> newOptionsForThisQuestion = originalOptions.stream()
                        .map(originalOption -> {
                            CollQuestionOption newOption = new CollQuestionOption();
                            BeanUtil.copyProperties(originalOption, newOption);
                            newOption.setId(null); // MP自动生成
                            newOption.setCollId(newCollId); // 新活动的ID
                            newOption.setQuestionId(newQuestion.getId()); // 新题目的ID
                            newOption.setGmtCreate(new Date());
                            newOption.setGmtModified(new Date());
                            return newOption;
                        }).collect(Collectors.toList());
                allNewOptions.addAll(newOptionsForThisQuestion);
            }
        }

        if (Lang.isNotEmpty(allNewOptions)) {
            questionOptionDao.saveBatch(allNewOptions);
        }
    }

}
